package com.demo.controller;

import com.demo.result.Result;
import com.demo.util.RedisOperator;
import com.demo.util.VerifyCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.http.client.support.BasicAuthenticationInterceptor;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.util.Base64Utils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@RestController
@RequestMapping("/loginController")
@Slf4j
public class LoginController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private RedisOperator redisOperator;

    private static final String REDIS_USER_CODEKEY = "verifyCode";

    private static final String GETTOKENURL = "http://localhost:9050/oauth/token";


    //用户登录接口
    @PostMapping("/login")
    public Result login(String username,String password,String codeKey,String codeKeyIndex){

        //通过redis检测验证码是否正确
        String verifyCode = redisOperator.get(REDIS_USER_CODEKEY + ":" + codeKeyIndex);
        log.info("接收到验证码: "+codeKey);
        log.info("verifyCode: "+verifyCode);
        if (!codeKey.equals(verifyCode)){
            return new Result(HttpServletResponse.SC_FORBIDDEN,null,"验证码不正确");
        }

        // 构建请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        // 构建请求体（请求参数）
        MultiValueMap<String,Object> paramsMap=new LinkedMultiValueMap<>();
        paramsMap.add("username", username);
        paramsMap.add("password", password);
        paramsMap.add("grant_type", "password");

        //利用密码模式到sso授权服务器中拿到access_token和refresh_token，因为是同一个项目的模块，可以使用密码模式
        //在请求头中带上客户端的账号密码
        HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(paramsMap, headers);
        // 设置 Authorization
        restTemplate.getInterceptors().add(
                new BasicAuthenticationInterceptor("WebClient","123456"));

        ResponseEntity<OAuth2AccessToken> result;

        try {
            //发送请求,从TokenEndpoint类中可以看到返回值是OAuth2AccessToken
            result = restTemplate.postForEntity(GETTOKENURL, entity, OAuth2AccessToken.class);
        }catch (HttpClientErrorException e){
            return new Result(HttpServletResponse.SC_FORBIDDEN,null,e.getMessage());
        }


        //处理返回结果
        if (result.getStatusCode()!= HttpStatus.OK){
            return new Result(HttpServletResponse.SC_UNAUTHORIZED,null,"登录失败");
        }

        //在这里也可以使用vo对象，封装好前端需要的数据返回，这个token如果以前设置了token加强信息，这里也能获取到
        return new Result(HttpServletResponse.SC_OK,result.getBody(),"登录成功");
    }




    //获取验证码的方法，将验证码存储到redis中
    @GetMapping("/getVerifyCode")
    public Result getVerifyCode() throws IOException {

        //1.生成验证码
        String codeKey = VerifyCodeUtils.generateVerifyCode(4);
        log.info("验证码:" + codeKey);
        //2.存储验证码 redis
        String codeKeyIndex = UUID.randomUUID().toString();
        //stringRedisTemplate.opsForValue().set(codeKey, code, 60, TimeUnit.SECONDS);
        redisOperator.set(REDIS_USER_CODEKEY+":"+codeKeyIndex,codeKey,500);
        //3.base64转换验证码
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        VerifyCodeUtils.outputImage(120, 60, byteArrayOutputStream, codeKey);
        String data = "data:image/png;base64," + Base64Utils.encodeToString(byteArrayOutputStream.toByteArray());
        //4.响应数据
        Map<String, String> map = new HashMap<>();
        map.put("data",data);
        map.put("codeKeyIndex",codeKeyIndex);

        return new Result(200,map,"获取验证码成功");
    }



    //重新登录，刷新令牌的使用,也要使用客户端id和密码进行查找新的令牌。备用
    @GetMapping("/refresh")
    public Result refresh(@RequestParam("refreshToken") String refreshToken){

        //从请求头中解析出refresh_token
        System.out.println(refreshToken);

        // 构建请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        MultiValueMap<String,Object> paramsMap=new LinkedMultiValueMap<>();
        paramsMap.add("grant_type", "refresh_token");
        paramsMap.add("refresh_token",refreshToken);

        //在请求头中带上客户端的账号密码
        HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(paramsMap, headers);

        //用refresh_token获取到新的access_token
        restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor("WebClient","123456"));

        OAuth2AccessToken token;
        try{
            token = restTemplate.postForObject(GETTOKENURL,entity,OAuth2AccessToken.class);
        }catch (HttpClientErrorException e){
            return new Result(HttpServletResponse.SC_FORBIDDEN,null,e.getMessage());
        }

        return new Result(200,token,"登录成功");
    }

}
